02 فصل دوم - تفکر پایتونی

فصل دوم

متغییر ها، عبارت ها و دستور ها

۲.۱ مقدار ها و نوع ها

یک مقدار یکی از پایه ای ترین چیز هایی است که یک برنامه با آن کار می کند، مثل یک حرف یا یک عدد. 'Hello, World!' ، 1 ، 2 مفدار هایی هستند که ما قبلا دیده ایم.

این مقادیر متعلق به انواع مختلفی هستند: 2 یک عدد صحیح ( integer )، و 'Hello, World!' یک رشته ( string ) است، دلیل نام گذاری آن این است که شامل یک "رشته" از حروف می باشد. شما ( و مفسر ) به این دلیل می توانید رشته ها را تشخیص بدهید که آنها شامل علامت های نقل قول ( quotation mark ) هستند.

اگر در مورد نوع یک مقدار اطمینان نداشتید، مفسر می تواند نوع آن را به شما بگوید.

>>> type (‘Hello, World’)

<type ‘str’>

>>> type(17)

<type ‘int’>

واضح است که رشته ها متعلق به نوع str هستند و اعداد صحیح متعلق به نوع int. اعداد با اعشار ده دهی متعلق به نوعی به نام float می باشد، به این خاطر که این اعداد در قالب اعداد شناور ( float-point ) ارئه می شود.

>>> type(3.2)

<type ‘float’>

در مورد مقدار هایی مثل '17' و '3.2' چه می شود گفت؟ آنها شبیه اعداد می باشند، اما در علامت هاي نقل قول مانند رشته ها قرار دارند.

>>> type(‘17’)

<type ‘str’>

>>> type(3.2)

<type ‘str’>

آنها رشته هستند.

موقع نوشتن یک عدد بزرگ ممکن است بخواهید از کاما بین بخش هایی از رقم ها استفاده کنید مثل 1,000,000 . این به عنوان یه عدد صحیح در پایتون قابل قبول نیست اما به نوعی دیگر قابل قبول است:

شکل ۲.۱: دیاگرام حالت

( state diagram )

>>> 1,000,000

(1, 0, 0)

بسیار خب، این چیزی نیست که ما انتظارش را داشتیم! پایتون 1,000,000 را به عنوان یک رشته ای از اعداد صحیح جدا شده توسط کاما تفسیر می کند. این اولین نمونه از خطای معنایی ( semantic error ) هست که مشاهده می کنیم: کد بدون تولید پیغام خطا اجرا می شود، اما کار صحيح را انجام نمی دهد.

۲.۲ متغییر ها

یکی از قدرتمند ترین امکانات زبان برنامه نویسی توانایی دستکاری متغییر ها است. یک متغییر یک اسم است که به یک مقدار اشاره دارد.

یک جمله انتصابی ( assignment statement ) یک متغییر جدید بوجود آورده و به آن مقدار می دهد:

>>> message = ‘And now for something completely different’

>>> n = 17

>>> pi = 3.1415926535897932

این مثال سه انتصاب می سازد. اولی، یک رشته را به یک متغییر جدید که message نام گذاری شده انتصاب می دهد؛ دومی عدد صحیح 17 را به n می دهد؛ سومی مقدار ( تقریبی ) را به pi نسبت می دهد.

یک راه متداول برای نمایش متغییر ها بر روی کاغذ نوشتن نام همراه با یک پیکان است که به مقدار متغییر اشاره می کند. این شکل از نمایش دیاگرام حالت ( state diagram ) نامیده می شود به این دلیل که حالتی که متغییر در آن هست را نمایش می دهد(به عنوان حالت متغییر ذهن در نظر بگیرید). شکل شماره ۲.۱ نتیجه حاصل از مثال قبل را نمایش می دهد.

نوع یک متغییر همان نوع مقداری است که به آن اشاره دارد.

>>> type(message)

<type ‘str’>

>>> type(n)

<type ‘int’>

>>> type(pi)

<type ‘float’>

تمرین ۲.۱: اگر یک عدد صحیح را موقع نوشتن با صفر شروع کنید با یک خطای گیج کننده مواجه خواهید شد:

>>> zipcode = 02492

SyntaxError: invalid token

اعداد دیگر به نظر می آید که کار می کنند، اما نتایج عجیب هستن:

>>> zipcode = 02132

>>> zipcode

1114

آیا می توانید علت را پیدا کنید؟ راهنمایی: مقدار های 01، 010، 0100 و 01000 را امتحان كنيد.

٢.٣ نام متغيير ها و كلمات كليدي

برنامه نويس ها معمولا نام هايي را براي متغييرهايشان انتخاب مي كنند كه با معني باشند، آنها دليل استفاده از متغييرشان را مستند مي كنند.

اسم متغییر ها می تواند طولانی باشد. آنها می توانند شامل هر دوی حروف و اعداد باشند، اما حتما باید با یک حرف شروع شوند. حروف بزرگ ( uppercase ) قابل قبول هستند ولی ایده ی خوبی است که اسم متغییر ها را با یک حرف کوچک ( lowercase ) شروع کنیم ( بعدا علت را خواهیم دید ).

حرف زیر خط ( underscore ) "_" می تواند در اسم استفاده شود، معمولا در اسم هایی بکار برده می شود که چند کلمه ای هستند مثل my_name یا airspeed_of_unladen_swallow.

اگر به یک متغییر نام نامعتبر بدهید با خطای نحوی (syntax error) مواجه خواهید شد:

>>> 76trombones = 'big parade'\ SyntaxError: invalid syntax\ >>> more@ = 1000000\ SyntaxError: invalid syntax\ >>> class = 'Advanced Theoretical Zymurgy'\ SyntaxError: invalid syntax\

76trombones نامعتبر است چرا که با یک حرف شروع نشده است. more@ نامعتبر است چون که شامل یک حرف نامعتبر (@) می باشد، اما مشکل class چیست؟

مشخص می شود که class یک کلمه کلیدی (keyword) در پایتون است. مفسر برای تشخیص ساختار برنامه از کلمات کلیدی استفاده می کند، و آنها نمی توانند به عنوان اسم متغییر استفاده شوند.

پایتون ۲ داری ۳۱ کلمه کلیدی است:

adddelformnotwhile

aselifglobalorwith

assertelseifpassyield

breakexceptimportprint

classexecinraise

continuefinallyisreturn

defforlambdatry

در پایتون ۳ exec دیگر کلمه کلیدی نیست، اما nonlocal هست.

ممکن است بخواهید این لیست را نگه دارید. اگر مفسر به یکی از اسم های متغییر هایتان ایراد گرفت و شما علتش را نمی دانستید، نگاه کنید که در این لیست هست یا نه.

۲.۴ عملگرها و عملوندها

عملگرها علائم اختصاصی ای هستند که محاسبتی مثل جمع و ضرب را فراهم می کنند. به مقدار هایی که عملگر ها بر روی آنها بکار گرفته می شوند، عملوند گفته می شود.

عملگرهای + ، - ، * ، / و ** به ترتیب نقش جمع، تفریق، ضرب، تقسیم و توان را ایفا می کنن، مشابه مثال های زیر:

20+32hour-1hour*60+minuteminute/605**2(5+9)*(15-7)

در برخی زبان های دیگر، \^ به عنوان توان استفاده می استفاده می شود، اما در پایتون به عنوان یک عملگر بیتی به نام XOR استفاده می شود. عملگرهای بیتی در این کتاب پوشش داده نمی شوند، اما می توانید درباره آنها اینجا مطالعه کنید:

http://wiki.python.org/moin/BitwiseOperators

در پایتون ۲، علامت تقسیم ممکن است کاری که شما انتظار دارید را انجام ندهد:

>>> minute = 59\ >>> minute/60\ 0

مقدار minute برابر با 59 است و در اصول محاسباتی تقسیم 59 بر 60 برابر با 0.98333 است نه 0. دلیل این ختلاف این است که پایتون تقسیم حد پایین (floor division) انجام می دهد. زمانی که هر دو عملوند ها عدد صحیح باشند نتیجه نیز عدد صحیح خواهد بود: تقسیم حد پایین مقدار اعشاری را حذف می کند، بنابراین این مثال به سمت صفر گرد می شود.

در پایتون ۳، نتیجه تقسیم اعشاری (float) است. عملگر جدید // تقسیم حد پایین را انجام می دهد.

چه عملوند ها اعداد ممیز شناور (اعشاری) باشند چه نه پایتون تقسیم اعشاری فراهم می کند و نتیجه نیز اعشاری است:

>>> minute/60.0\ 0.98333333333333328

۲.۵ عبارت ها و جمله ها

یک عبارت (expression) ترکیبی از مقدارها، متغییرها و عملگرهاست. یک مقدار به تنهایی یک عبارت در نظر گرفته می شود و همچنین یک متغییر و همه عبارات قانونی (فرض کنید یک مقدار به متغییر x منتسب شده):

17

x

x + 17

یک جمله (statement) یک تکه کدی است که مفسر پایتون می تواند آن را اجرا کند. ما دو نوع جمله قبلا دیدم: print و انتصاب.

اصولا یک عبارت خودش یک جمله است اما اگر این دو را متفاوت از هم در نظر بگیرم ساده تر است. تفاوت مهم اینجاست که یک عبارت شامل یک متغییر است درصورتی که در مورد یک جمله اینطور نیست.

۲.۶حالت تعاملی و حالت اسکریپتی

یکی از فواید کار با زبان‌های مفسری این است که می‌توانید مقدار کمی از کد را در حالت تعاملی تست کنید، قبل از اینکه آنها را در یک اسکریپت ( فایل اسکریپت ) قرار بدهید.

برای مثال اگر از پایتون به عنوان یک ماشین حساب استفاده کنید احتمالاً می‌نویسید:

>>> miles = 26.2

>>> miles * 1.61

42.18

اولین خط انتصاب یک مقدار به متغییر miles است، اما اثر ( نتیجه ) قابل مشاهده ای ندارد. خط دوم یک عبارت است که مفسر آن را ارزیابی می‌کند. و در نتایج نمایش می‌دهد. بنابراین یاد گرفتیم که ماراتون در حدود ۴۲ کیلومتر است.

اما اگر همان کد را در یک اسکریپت قرار بدهید و اجرا کنید، خروجی ای دریافت نخواهید کرد. در حالت اسکریپتی ( Script mode ) یک عبارت اثر قابل مشاهده ندارد. در حقیقت پایتون یک عبارت را ارزیابی می‌کند. اما تا زمانی که به آن گفته نشود مقدارش را نمایش نمی‌دهد.

miles = 26.2

print miles * 1.61

این رفتار در ابتدا ممکن است کمی گیج کننده باشد.

یک اسکریپت شامل رشته ای از جمله‌هاست که اگر بیش از یک جمله وجود داشته باشد نتایج در همان لحظه اجرای آن جمله ظاهر می‌شود.

برای مثال، این اسکریپت

print 1

x = 2

print x

نتایج خروجی

1

2

جمله انتصاب هروجی ای تولید نمی‌کند.

تمرین ۲.۲. جملات زیر را در مفسر پایتون وارد کنید و ببینید چه کاری انجام می‌دهند:

5

x = 5

x + 1

حالا همان جمله ها را در یک اسکریپت بگذارید و آن را اجرا کنید. خروجی چیست؟ با استفاده از تبدیل هر عبارت به یک جمله چاپ ( print ) اسکرپیت را تغییر داده و دوباره اجرا کنید.

۲.۷ ترتیب عملگرها

وقتی بیش از یک عملگر در یک عبارت داریم،ترتیب ارزش گذاری‌ها براساس قوانین اولویت ( rules of precedence ) است. برای عملگرهای ریاضی پایتون از قرارداد ریاضی پیروی میکند. سر نام پتضتجت‌ ( PEMDAS ) روش مناسبی برای بخاطر سپردن این قوانین است:

  • پرانتزها دارای بالاترین اولویت هستند و می‌توانند یک عبارت را محبور کنند به ترتیبی که میخواهید عمل کنند.از آنجایی که عبارت‌های داخل پرانتز اولین مقدارهایی هستند که ارزیابی می‌شوند (1-3) * 2 برابر با 4 و (2-5) ** (1+1) برابر با ۸ است. همچنین می‌توانید از پرانتز برای خوانایی ساده تر جملات استفاده کنید. مثل 60 / (100*minute)، حتی اگر تغییری در نتایج ایجاد نشود.
  • توان دومین اولویت بالا را دارد. بنابراین 1+2**2 برابر با 3 است نه 4 و 3**1*3 برابر 3 است نه 27.
  • ضرب و تقسیم هر دو یک اولویت را دارند و اولویت آنها بالاتر از ‌جمع و تفریق است که این دو نیز اولویت یکسان دارند. پس 1-3*2 برابر با 5 است نه 4 و 2/4+6 برابر با 8 است نه 5
  • عملگر ها با اولویت یکسان از چپ به راست ارزیابی میشوند( بجز توان ) بنابراین عبارت degrees/2*pi ابتدا عملگر تقسیم اتفاق می اوفتد و سپس نتایج آن با pi ضرب می‌شود. برای تقسیم کردن به ۲pi میتوانید از پرانتز استفاده کنید یا بنویسد degrees/2/pi.

من خیلی تلاش نمیکنم که قوانین اولویت ها برای عملگر ها را به خاطر بسپارم، اگر نتوانم با دیدن یک جمله اولویت ها را تشخیص بدهم از پرانتز برای مشخص کردن استفاده می کنم.

۲.۸ به طور عمومی، نمی توانید از عملگرهای ریاصی بر روی رشته ها استفاده کنید حتی اگر آنها به شکل اعداد باشند، بنابراین مثال های زیر غیر قابل قبول هستند:

‘2’ - ‘1’‘eggs’ / ‘easy’‘third’ * ‘ a charm’

عملگر + بر روی رشته ها کار می کند اما احتمالا آن چیزی که انتظار دارید نیست. این عکلگر در اینجا عمل الحاق ( Concatenation ) را فراهم میکند: اتصال دو رشته با چسباندن آنها به صورت لب به لب برای مثال:

first = ‘throat’

second = ‘warbler’

print first + second

خروجی این برنامه برابر throatwarbler است.

عملگر * نیز بر روی رشته ها کار میکند، این عملگر عمل تکرار را فراهم میکند. برای مثال، 3 * 'Spam' برابر 'SpamSpamSpam' می‌شود. اگر یکی از دو عملوند رشته باشد عملوند دیگر باید عدد صحیح باشد.

این کاربرد + و * با مفهموم عمل جمع و ضرب متناسب است. به عنوان نمونه 3*4 برابر است با 4+4+4 پس انتظار داریم 3 * 'Spam' نیز به همان ترتیب 'Spam' + 'Spam' + 'Spam' باشد وهست. از طرف دیگر یک راه قابل توجهی وجود دارد که الحاق و تکرار رشته را از جمع و ضرب عدد صحیح متفاوت می کند. آیا می تواند به یکی از ویژگی های عمل جمع که الحاق ندارد اشاره کنید؟

۲.۹ توضیح ( comments )

به همان میزان که یک برنامه بزرگتر و پیچیده تر می شود، خوانایی آن نیز کم تر می شود. زبان های رسمی ( معمول )‌ متراکم هستند و فهمیدن و درک چرای یک کد با یک نگاه کردن کار سختی است.

به همین دلیل ایده خوبی است که به برنامه ها یادداشت اضافه کنیم که به زبان طبیعی ( انسانی ) توضیح بدهد که برنامه چه کاری انجام میدهد. به این یادداشت ها توضیح گفته می شود و آنها با علامت # شروع می شوند:

# compute the percentage of the hour that has elapsed

percentage = (minute * 100) / 60

در این مورد توضیح خودش به تنهایی ابتدای خط امده است. همچنین می شود توضیح را در انتهای خط قرار داد.

percentage = (minute * 100) / 60 # percentage of an hour

هر چیزی از علامت # تا پایان آن خط نادیده گرفته می شود - و هیچ تاثیری بر روی برنامه نخواهد داشت.

توضیح ها زمانی که برای مستند سازی قابلیت های غیر شفاف به کار روند کاربردی تر خواهند بود. منطقی است که در نظر داشته باشید که خواننده بتواند بفهمد که کد چه کاری انجام می دهد. خیلی بیشتر مفید است که چرایی آن را توضیح بدهد.

این توضیح بی مصرف و اضافی است:

v = 5 # assign 5 to v

این توضیح اطلاعات مفیدی دارد که در کد نیست:

v = 5 # velocity in meters/second

نام خوب برای متغییر نیاز به توضیح را کم می کند، اما نام های طولانی عبارت های پیچیده ای درست میکنند که خوانایی را سخت می کند. بنابراین تعادلی ( معاوضه ) در اینجا وجود دارد.

۲.۱۰ خطایابی ( debugging )

در اینجا اغلب خطاهای نحوی‌ای ( syntax error ) که ممکن است شما به وجود آورید انتخاب نام نامعتبر است: مثل class، yield که کلمات کلیدی هستند. یا add\~job و US\$ که شامل حروف نامعتبر هستند.

اگر بین نام یک متغییر فاصله گذاری کنید، پایتون آنها را دو عملوند بدون وجود عملگر در بینشان در نظر می‌گیرد.

برای خطاهای نحوی، پیام خطا کمک چندانی نمی‌کند، بیشتر پیام‌های معمول Syntax Error: invalid Syntax و Syntax Error: invalid token هستند که هیچکدام اطلاعات مفیدی نمی‌دهند

خطای زمان اجرا ( runtime error ) که اغلب با آن مواجه می‌شوید یک "استفاده قبل از تعریف" ( "use befor def" ) است که نلاش برای استفاده از یک متغییر قبل از مقدار دهی آن می‌باشد.حتی اگر اسم یک متغییر را اشتباه بنویسید ممکن ایت این خطا رخ دهد:

>>> principal = 327.68

>>> interest = principle * rate

NameError: name ‘principle’ is not defined

نام متغییر حساس به حرف ( case sensitive ) است. بنابراین LaTeX با latex یکسان نیست.

در حال حاضر بیشترین مورد خطای معنایی ( semantic error )، ترتیب قرار دادن عملگرهاست. برای نمونه برای محاسبه 1/2p: احتمالا خواهید نوشت:

>>> 1.0 / 2.0 * pi

اما عمل تقسیم ابتدا اتفاق می‌افتد بنابراین p/2 را دریافت خواهید کرد که همان مقدار نیست! هیج راهی وجود ندارد که پایتون بفهمد منظور شما چه بوده است بنابراین پیام خطا دریافت نخواهید کرد و فقط جواب غلط می‌گیرید.

۲.۱۱ واژه نامه

مقدار ( value ): یکی از پایه‌ای ترین واحدهای داده مثل اعداد با رشته که یک برنامه دستکاری ( اداره - کنترل ) می‌کند.

نوع ( type ): یک طبقه بندی از مقدارها. نوع هایی که تا اینجا دیدیم اعداد صحیح ( نوع int )، اعداد اعشار شناور ( نوع float ) و رشته ها ( نوع str ) هستند.

اعداد صحیح ( integer ): یک نوع که یک عدد کامل را ارائه می‌دهد.

اعداد اعشار شناور ( float-point ): یک نوع که اعداد کثری ( اعداد با اعشار ) ارائه می‌دهد.

رشته ( String ): یک نوع که دنباله‌ای از حروف را ارائه می‌دهد.

متغییر ( variable ): یک نام که به یک مقدار اشاره دارد.

جمله ( statement ): یک تکه از کد که یک دستور یا فعالیتی را فراهم می‌کند. بنابراین جمله‌هایی که ما تا به اینجا دیدیم

انتصاب ( assignment ): یک جمله که یک مقدار به یک متغییر نسبت می‌دهد.

دیاگرام حالت (state diagram): یک نمایش گرافیکی از مجموعه ای از متغییرها و مقدار های اشاره شده با آنها.

کلمه کلیدی (keyword): یک کلمه رزرو شده توسط کامپایلر که از آن برای تجزیه و تحلیل(parse) برنامه استفاده می‌کند. به عنوان نمونه نمی‌توانید از کلمات کلیدی if و def و … به عنوان نام متغییر استفاده کنید.

عملگر (Operator): یک علامت(symbol) خاص که یک محاسبات ساده مانند جمع، ضرب و یا الحاق رشته را فراهم می‌کند.

عملوند (Operand): یکی از مقدار هایی که عمگر روی آن عمل می‌کند.

جزء صحیح پایین (floor division): عملگری است که مقدار اعشاری حاصل از تقسیم دو عدد را حذف می‌کند.

عبارت (expression): ترکیبی از متغییر، عملگر و مقدارها که یک مقدار را نتیجه می‌دهد.

ارزیابی (evaluate): ساده سازی یک عبارت با انجام عمگرها نا حصول یک مقدار واحد.

قانون اولیت‌ها (rules of precedence): یک مجموعه از قوانین حکم فرما است که ترتیب ارزیابی عملگرها و عملوند ها را در یک عبارت ترکیبی تعیین می‌کند.

الحاق (concatenate): چسباندن دو رشته به صورت پشت سر هم.

توضیح (comment): اطلاعاتی در یک برنامه که برای برنامه نویسان ( یا کسی که کد منبع را می‌خواند ) نوشته شده است و در اجرای برنامه تاثیری ندارد.

۲.۱۲ تمرین‌ها

تمرین ۲.۳. فرض کنید انتصاب های زیر را اجرا کردیم:

width = 17

height = 12.0

delimiter = ‘.’

به ازای هر کدام از عبارت ها مقدار آن و نوع ( نوع مقدار حاصل از عبارت) را بنویسید.

  1. width / 2
  2. width / 2.0
  3. height / 3
  4. 1 + 2 * 5
  5. delimiter * 5

از مفسر پایتون برای چک کردن جواب‌هایتان استفاده کنید.

تمرین ۲.۴. برای تمرین از مفسر پایتون را به عنوان ماشین حساب استفاده کنید:

  1. حجم یک کره با شعاع r برابر است. حجم کره ای یا شعاع ۵ چقدر است؟ راهنمایی: ۳۹۲.۷ اشتباه است!
  2. فرض کنید نسخه چاپی یک کتاب ۲۴.۹۵ دلار است، اما کتاب فروشی یک تخفیف ۴۰ درصدی گذاشته است. هزینه حمل و نقل برای یک نسخه ۳ دلار بوده و به ازای هر نسخه بیشتر، ۷۵ سنت اضافی می‌گردد. قیمت تمام شده برای ۶۰ نسخه چقدر است؟
  3. اگر من خانه را در ساعت ۶:۵۲ دقیقه صبح و یک مایل را با سرعت ارام (۸:۱۵ بر مایل)، سپس ۳ مایل را سریع (۷:۱۲ بر مایل ) و یک مایل دوباره با سرعت آرام بدوم چه زمانی من برای صرف صبحانه به خانه می رسم؟